import copy
import re

from string import Template
import jsonpath
import yaml
from jinja2.nodes import TemplateData
from urllib3 import request

from commons.yaml_util import write_yaml, read_all
from hotLoad.debug_talk import DebugTalk


class ExtractUtil:
    # 后四个参数对应yaml文件的保存值的变量名: [提取地方（提取值的前面是什么）,提取方式,提取之后的下标]
    def extract(self, res, var_name, attr_name, expr:str, index):
        # 深拷贝res，这样对new_res的修改不会影响到res
        print(f"res打印{res}")
        new_res = copy.deepcopy(res)
        # 特殊处理：把json()方法改成json属性，因为变成属性才能通过反射去获取属性的值
        try:
            new_res.json = new_res.json()
        except Exception:
            new_res.json = {"msg":'response not json data'}

        # 反射取值
        data = getattr(new_res, attr_name)
        print(f"data===============:{data}")

        # 判断该用json还是正则表达式来提取数据（根据expr字段）
        if expr.startswith("$"):
            print(f"尝试从 data 中提取 JSONPath 表达式 {expr}")
            lis = jsonpath.jsonpath(dict(data),expr)
            print("\nJSONPath提取返回来的值:", lis)
        else:
            lis = re.findall(expr,data)
            print("\n正则表达式返回来的值:", lis)

        # 获取到之后 通过下标取值 写入extract.yaml文件
        if lis:
            write_yaml({var_name:lis[index]})

    # 解析使用变量 把${access_token}替换成从extract.yaml里面提取的具体值
    def change(self, request_data: dict):
        # 将字典转为字符串
        data_str = yaml.safe_dump(request_data)
        # 用模版实现字符串替换
        extracted_values = read_all()
        print("从YAML中提取的数据:", extracted_values)
        # 将extract.yaml里的所有值读取出来然后根据变量名替换到数据字符串中
        # new_request_data = Template(data_str).safe_substitute(extracted_values)
        new_request_data = self.hotload_replace(data_str)
        # 再转换为字典后返回
        data_dict = yaml.safe_load(new_request_data)
        return data_dict

    # Template模版替换会将整数字符串解析成整数，所以我们使用httprunner框架的热加载去实现字符串替换
    def hotload_replace(self,data_str:str):
        # 定义一个正则匹配的表达式
        # reg_exp = "\\$\\{(.*?)\\}"            # 表示${(.*?)}，\\是转义字符  (.*?)代表全部字符
        regexp = "\\$\\{(.*?)\\((.*?)\\)\\}"     # 表示${函数名(参数)}

        # 通过正则表达式在data_str字符串中去匹配，找到所有的表达式 装进list
        fun_list = re.findall(regexp, data_str)
        #print(fun_list)

        # 对获取到的表达式（函数）进行处理
        # f[0]是参数名 f[1]是参数
        for f in fun_list:
            print(f)
            if f[1] == "":      # 无参函数处理
                new_value = getattr(DebugTalk(),f[0])()     # 用反射获取函数名
                print(f"value1:{new_value}")
            else:               # 有参函数
                # 对有多个参数的函数，先用逗号分割字符串变成参数列表，然后解包传递（单个参数时不能分割）
                new_value = getattr(DebugTalk(),f[0])(*f[1].split(","))
                print(f"value2:{new_value}")

            # 如果value是数字格式的字符串
            if isinstance(new_value,str) and new_value.isdigit():
                new_value = "'" + new_value + "'"

            #将旧的值替换成新的值后返回
            old_value = "${" + f[0] + "(" + f[1] + ")}"
            data_str = data_str.replace(old_value,str(new_value))
        return data_str

# if __name__ == '__main__':
#     request_data = {"method":"get",
#                     "url":"www.baidu.com",
#                     "data":"${read_yaml(number)}",
#                     "params":"${add(1,2)}",
#                     "json":"${get_random_number()}"}
#     data_str = yaml.safe_dump(request_data)
#     ExtractUtil().hotload_replace(data_str)